using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;
using ERF;
using FirstPerson.States;
using FirstPerson.Objects.Pickups;
using ERF.Input;

namespace FirstPerson
{
    /// <summary>
    /// This is the main type for your game
    /// </summary>
    public class Game1 : ERFGame
    {
        private SceneGraph currentSceneGraph;
        private Camera camera;
        private SoundHandler sound;
        private NetworkHandler networkHandler;
        private PlayerHandler playerHandler;
        private InputHandler input;
        private StateMachine stateMachine;


        public override StateMachine StateMachine
        {
            get { return stateMachine; }
        }

        public override IInputHandler Input
        {
            get { return input; }
        }


        public override SceneGraph CurrentSceneGraph
        {
            get
            {
                return this.currentSceneGraph;
            }
            set
            {
                this.Components.Remove(this.currentSceneGraph);
                this.currentSceneGraph = value;
                this.Components.Add(this.currentSceneGraph);
            }
        }

        public override Camera Camera
        {
            get { return this.camera; }
            set {
                this.Components.Remove(this.camera);
                this.camera = value;
                this.Components.Add(this.camera);
            }
        }

        public override SoundHandler SoundHandler
        {
            get { return this.sound; }
        }
        public override ERF.NetworkHandler NetworkHandler
        {
            get { return this.networkHandler; }
        }
        public override ERF.PlayerHandler PlayerHandler
        {
            get { return this.playerHandler; }
        }

        public Game1()
        {
            //graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";

            //this.particleSystem.DrawOrder = 100;
        }


        /// <summary>
        /// Allows the game to perform any initialization it needs to before starting to run.
        /// This is where it can query for any required services and load any non-graphic
        /// related content.  Calling base.Initialize will enumerate through any components
        /// and initialize them as well.
        /// </summary>
        protected override void Initialize()
        {
            sound = new SoundHandler(this);
            this.Components.Add(this.sound);
            
            this.InitializeInput();

            Components.Add(new GamerServicesComponent(this));

            InitStates();
            this.networkHandler = new NetworkHandler(this);
            this.playerHandler = new PlayerHandler(this);

            base.Initialize();
        }


        private void InitStates()
        {
            stateMachine = new StateMachine(this);
            stateMachine.CurrentState = StartMenuState.GetInstance(stateMachine);
            this.Components.Add(stateMachine);
        }

        private void InitializeInput()
        {
            this.input = new InputHandler(this);

            /*
             * Keyboard + Mouse section...
             */
#if !XBOX
            this.input.AssignButton("FORWARD_BUTTON", new AssignedKeyboardButton(this.input, Keys.W));
            this.input.AssignButton("BACKWARD_BUTTON", new AssignedKeyboardButton(this.input, Keys.S));
            this.input.AssignButton("STRAFE_LEFT_BUTTON", new AssignedKeyboardButton(this.input, Keys.A));
            this.input.AssignButton("STRAFE_RIGHT_BUTTON", new AssignedKeyboardButton(this.input, Keys.D));

            this.input.AssignButton("JUMP_BUTTON", new AssignedKeyboardButton(this.input, Keys.Space));
            this.input.AssignButton("SHOOT_BUTTON", new AssignedMouseButton(this.input, AssignedMouseButton.Buttons.LEFT));

            this.input.AssignButton("MENU_UP", new AssignedKeyboardButton(this.input, Keys.Up));
            this.input.AssignButton("MENU_DOWN", new AssignedKeyboardButton(this.input, Keys.Down));
            this.input.AssignButton("MENU_RIGHT", new AssignedKeyboardButton(this.input, Keys.Right));
            this.input.AssignButton("MENU_LEFT", new AssignedKeyboardButton(this.input, Keys.Left));
            this.input.AssignButton("MENU_SELECT", new AssignedKeyboardButton(this.input, Keys.Enter));
            this.input.AssignButton("MENU_BACK", new AssignedKeyboardButton(this.input, Keys.Escape));

            this.input.AssignButton("MENU_BUTTON", new AssignedKeyboardButton(this.input, Keys.Escape));

            this.input.AssignDevice("AIM", new MouseDevice(this.input,this,MouseDevice.MouseTypes.AIM));
            this.input.AssignButton("TOGGLE_DEBUG", new AssignedKeyboardButton(this.input, Keys.F1));

            this.input.AssignButton("SHOW_SCORE", new AssignedKeyboardButton(this.input, Keys.Tab));

            this.input.AssignButton("TOGGLE_FULLSCREEN", new AssignedKeyboardButton(this.input, Keys.F11));

#endif

            /*
             * GamePad section
             */
            this.input.AssignButton("JUMP_BUTTON", new AssignedGamepadButton(this.input, Buttons.LeftTrigger));
            this.input.AssignButton("SHOOT_BUTTON", new AssignedGamepadButton(this.input, Buttons.RightTrigger));

            this.input.AssignButton("MENU_UP", new AssignedGamepadButton(this.input, Buttons.LeftThumbstickUp));
            this.input.AssignButton("MENU_DOWN", new AssignedGamepadButton(this.input, Buttons.LeftThumbstickDown));
            this.input.AssignButton("MENU_RIGHT", new AssignedGamepadButton(this.input, Buttons.LeftThumbstickRight));
            this.input.AssignButton("MENU_LEFT", new AssignedGamepadButton(this.input, Buttons.LeftThumbstickLeft));
            this.input.AssignButton("MENU_UP", new AssignedGamepadButton(this.input, Buttons.DPadUp));
            this.input.AssignButton("MENU_DOWN", new AssignedGamepadButton(this.input, Buttons.DPadDown));
            this.input.AssignButton("MENU_RIGHT", new AssignedGamepadButton(this.input, Buttons.DPadRight));
            this.input.AssignButton("MENU_LEFT", new AssignedGamepadButton(this.input, Buttons.DPadLeft));

            this.input.AssignButton("MENU_SELECT", new AssignedGamepadButton(this.input, Buttons.A));
            this.input.AssignButton("MENU_BACK", new AssignedGamepadButton(this.input, Buttons.B));

            this.input.AssignButton("MENU_BUTTON", new AssignedGamepadButton(this.input, Buttons.Back));

            this.input.AssignDevice("MOVE", new GamePadDevice(this.input,GamePadDevice.DeviceSource.LeftStick,false));
            this.input.AssignDevice("AIM", new GamePadDevice(this.input,GamePadDevice.DeviceSource.RightStick,true));
            this.input.AssignButton("TOGGLE_DEBUG", new AssignedGamepadButton(this.input, Buttons.Back));

            this.input.AssignButton("SHOW_SCORE", new AssignedGamepadButton(this.input, Buttons.LeftShoulder));
        }

        /// <summary>
        /// LoadContent will be called once per game and is the place to load
        /// all of your content.
        /// </summary>
        protected override void LoadContent()
        {

        }

        /// <summary>
        /// UnloadContent will be called once per game and is the place to unload
        /// all content.
        /// </summary>
        protected override void UnloadContent()
        {
            // TODO: Unload any non ContentManager content here
        }

        /// <summary>
        /// Allows the game to run logic such as updating the world,
        /// checking for collisions, gathering input, and playing audio.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        protected override void Update(GameTime gameTime)
        {
            input.Update(gameTime);

            if (input.IsButtonReleased("TOGGLE_FULLSCREEN"))
                this.ToogleFullscreen();

            base.Update(gameTime);
        }

        /// <summary>
        /// This is called when the game should draw itself.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        protected override void Draw(GameTime gameTime)
        {
            GraphicsDevice.Clear(Color.Black);
            //GraphicsDevice.RenderState.FillMode = FillMode.WireFrame;
            // TODO: Add your drawing code here

            base.Draw(gameTime);
        }

        public override void SetResolution(int width, int height)
        {
            base.SetResolution(width, height);

            // If a camera has been set in the game, we adjust its aspectratio.
            if (this.camera != null)
                this.camera.AspectRatio = this.GraphicsDevice.Viewport.AspectRatio;
        }

        public override void ToogleFullscreen()
        {
            base.ToogleFullscreen();
            this.camera.AspectRatio = this.GraphicsDevice.Viewport.AspectRatio;
        }
    }
}
